import errno
import fcntl
import os
import select
import socket
import sys

if len(sys.argv) < 2:
    print('Usage: msock <a:p> [bind_a:bind_p]')
    sys.exit(0)

OUT_AP = sys.argv[1].split(':')
OUT_AP[1] = int(OUT_AP[1])
OUT_AP = tuple(OUT_AP)

AP = ('localhost', 5555)

if len(sys.argv) > 2:
    AP = sys.argv[1].split(':')
    AP[1] = int(AP[1])
    AP = tuple(AP)

MAX_LISTEN=5
READ_BUFFER=1024

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(AP)
s.listen(MAX_LISTEN)

o = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
o.connect(OUT_AP)
o.setblocking(0)

fcntl.fcntl(sys.stdin, fcntl.F_SETFD, os.O_NONBLOCK)

clients = []

while True:
    r = clients + [s, o, sys.stdin]
    w = []
    e = []
    r, w, e = select.select(r, w, e)

    for io in r:
        if io == s:
            client, _ = s.accept()
            client.setblocking(0)
            clients.append(client)
        elif io == o:
            try:
                b = io.recv(READ_BUFFER)
            except IOError, e:
                if e.errno == errno.EAGAIN:
                    continue
                raise
            if b == '':
                sys.exit()
            sys.stdout.write(b)
            for c in clients:
                c.send(b)
        elif io == sys.stdin:
            try:
                b = io.read(1)
            except IOError, e:
                if e.errno == errno.EAGAIN:
                    continue
                raise
            o.send(b)
        else:
            try:
                b = io.recv(READ_BUFFER)
            except IOError, e:
                if e.errno == errno.EAGAIN:
                    continue
                raise
            if b == '':
                io.close()
                clients.remove(io)
            o.send(b)
